﻿'    Open Subtitle Editor
'    Copyright (c) 2009-2010 Discovery OSS Team
'
'    This file is part of Open Subtitle Editor.
'
'    Open Subtitle Editor is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 3 of the License, or
'    (at your option) any later version.
'
'    Open Subtitle Editor is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.
'
'    You should have received a copy of the GNU General Public License
'    along with Open Subtitle Editor.  If not, see <http://www.gnu.org/licenses/>.


' Generic functions & variables of the program go here.

Module Generic
    Public langFileReader As System.IO.StreamReader
    Public fileWriter As System.IO.StreamWriter
    Public AppRegKey As String = "HKEY_CURRENT_USER\Software\" & Application.CompanyName & "\" & Application.ProductName
    Public currentLanguageFile As String
    Public newLine As String = Chr(13) & Chr(10)
    Public DecimalSeparator As String = Mid(1 / 2, 2, 1)
    Public movieLoaded As Boolean
    Public incompleteLanguageFile As Boolean

    ' Add a line to the debug list
    Public Sub addToDebugList(ByVal text As String)
        frmMain.tmrDebug.Enabled = False
        frmMain.tick = 0
        frmMain.lstDebug.Items.Insert(0, TimeOfDay & " - " & text)
        'frmMain.tmrDebug.Enabled = True ' TODO: Remove comment here
        If Not frmMain.tabControl.SelectedTab Is frmMain.tabDebug Then
            frmMain.tabDebug.ImageKey = "information"
        End If
    End Sub

    ''' <summary>
    ''' Load a string from the translation file.
    ''' </summary>
    ''' <param name="text">The string that is used to identify the translation string inside the SEL file
    ''' and around the program</param>
    ''' <returns>Returns translated string only if found.</returns>
    ''' <remarks>Doesn't always return value, will call "loadTranslation" to reset to English if the wanted
    ''' string is not found.</remarks>
    Public Function loadStringFromLangFile(ByVal text As String, Optional ByVal fallback As Boolean = False) As String
        Dim currentLine As String
        Dim currentFields(2) As String

        If Not fallback Then
            langFileReader = My.Computer.FileSystem.OpenTextFileReader(My.Computer.Registry.GetValue(AppRegKey, "LanguageFile", Nothing))
        Else
            langFileReader = My.Computer.FileSystem.OpenTextFileReader(Application.StartupPath & "\Languages\English.sel")
        End If

        While Not langFileReader.EndOfStream
            currentLine = langFileReader.ReadLine
            If Not currentLine = "" And Not Microsoft.VisualBasic.Left(currentLine, 1) = "!" Then
                currentFields = Split(currentLine, ",", "2")
                If currentFields(0) = text Then
                    langFileReader.Close()
                    Return LTrim(currentFields(1))
                End If
            End If
        End While
        addToDebugList("Could not find translated line for entry " & """" & text & """" & ".")
        langFileReader.Close()
        If My.Computer.Registry.GetValue(AppRegKey, "LanguageFile", Nothing) = Application.StartupPath & "\Languages\English.sel" Then
            pauseForCriticalError()
            Return Nothing
        Else
            Return loadStringFromLangFile(text, True)
        End If

    End Function

    Public Sub pauseForCriticalError()
        MsgBox("A critical error has occured. Last debug message was:" & (Chr(13) & Chr(10)) & (Chr(13) & Chr(10)) & frmMain.lstDebug.Items.Item(0), MsgBoxStyle.Critical)
        Try
            fileWriter = My.Computer.FileSystem.OpenTextFileWriter(Application.LocalUserAppDataPath & "\debug " & " " & DateString & " " & Format(Now, "hh.mm.ss") & ".txt", False)
            addToDebugList("Succesfully opened debug file.")
            For i = 0 To frmMain.lstDebug.Items.Count - 1
                fileWriter.WriteLine(frmMain.lstDebug.Items.Item(i))
            Next
            addToDebugList("Succesfully wrote all items to debug file.")
            fileWriter.Close()
            addToDebugList("Succesfully closed debug file.")
        Catch ex As Exception
            addToDebugList("WARNING: Could not create or write to debug file.")
        End Try
    End Sub

    Public Sub loadTranslation(ByVal loadType As Short)
        ' loadtype:
        ' 0 = Open Load Translation dialog
        ' 1 = Load From Registry
        ' 2 = Reset To English

        If loadType = 0 Then

            frmMain.dlgOpen.Filter = loadStringFromLangFile("languagefile") & " (*.sel)|*.sel"
            frmMain.dlgOpen.InitialDirectory = Application.StartupPath & "\Languages"
            If frmMain.dlgOpen.ShowDialog() = Windows.Forms.DialogResult.OK Then
                langFileReader = My.Computer.FileSystem.OpenTextFileReader(frmMain.dlgOpen.FileName)
                If Not langFileReader.ReadLine = "! Actual Open Subtitle Editor Language File" Then
                    addToDebugList("File selected was not a Subtitle Editor language file, resetting to English.")
                    loadTranslation(2)
                    Exit Sub
                End If
                currentLanguageFile = frmMain.dlgOpen.SafeFileName
                My.Computer.Registry.SetValue(AppRegKey, "LanguageFile", frmMain.dlgOpen.FileName)
            Else
                Exit Sub
            End If

        ElseIf loadType = 1 Then
            Try
                langFileReader = My.Computer.FileSystem.OpenTextFileReader(My.Computer.Registry.GetValue(AppRegKey, "LanguageFile", Nothing))
                Dim temp() As String = Split(My.Computer.Registry.GetValue(AppRegKey, "LanguageFile", Nothing), "\")
                currentLanguageFile = temp(temp.Count - 1)
            Catch langNotFound As Exception
                addToDebugList("Saved Language file could not be found. Resetting to English.")
                loadTranslation(2)
                Exit Sub
            End Try

        ElseIf loadType = 2 Then

            Try
                langFileReader = My.Computer.FileSystem.OpenTextFileReader(Application.StartupPath & "\Languages\English.sel")
                My.Computer.Registry.SetValue(AppRegKey, "LanguageFile", Application.StartupPath & "\Languages\English.sel")
                incompleteLanguageFile = False
            Catch dirNotFound As System.IO.DirectoryNotFoundException
                addToDebugList("CRITICAL: Languages directory not found! Verify correct installation and contact the project administrator!")
                pauseForCriticalError()
            Catch fileNotFound As System.IO.FileNotFoundException
                addToDebugList("CRITICAL: English language file not found! Verify correct installation and contact the project administrator!")
                pauseForCriticalError() 
            End Try

        End If

        frmMain.LoadLangStrings()
        frmPreviewSettings.LoadLangStrings()
        frmAbout.LoadLangStrings()
        frmLicense.LoadLangStrings()
        frmUnknownFormat.LoadLangStrings()

        If incompleteLanguageFile = True Then
            MsgBox("The translation file you've chosen (" & currentLanguageFile & ") is incomplete or corrupted." & newLine & newLine & "You can visit the program's website to see if a translation file compatible with the version you're using (" & VersionNumberInterpretation() & ") is available." & newLine & newLine & "The program will now reset to English.", MsgBoxStyle.Exclamation)
            loadTranslation(2)
        End If

        If Not frmMain.getFirstDebugListItem = loadStringFromLangFile("succesfulload") Then
            addToDebugList(loadStringFromLangFile("succesfulload"))
        End If
        incompleteLanguageFile = False

    End Sub

    Public Sub openMovie()
        Dim fileWord, allFiles As String
        fileWord = loadStringFromLangFile("fileWord")
        allFiles = loadStringFromLangFile("allFiles")
        frmMain.dlgMovOpen.Filter = "AVI " & fileWord & " (*.avi)|*.avi|MPEG " & fileWord & " (*.mpg;*.mpeg)|*.mpg;*.mpeg|" & _
                                    allFiles & " (*.*)|*.*"
        If frmMain.dlgMovOpen.ShowDialog = DialogResult.OK Then
            frmMain.mPlayer.URL = frmMain.dlgMovOpen.FileName
            frmMain.mPlayer.settings.volume = 100
            addToDebugList(loadStringFromLangFile("loadedmovie"))
            frmMain.mPlayer.Visible = True
            movieLoaded = True
            frmMain.ViewTabsToolStripMenuItem.Checked = True
            frmMain.sldPosition.Value = 0
            frmMain.sldPosition.Maximum = 0
            updateTitle()
        End If
    End Sub

    Public Function convertShowHideCellToMiliseconds(ByVal showHideValue As String) As Integer
        Dim hoursTemp As Short = Microsoft.VisualBasic.Mid(showHideValue, 1, 2)
        Dim minutesTemp As Short = Microsoft.VisualBasic.Mid(showHideValue, 4, 2)
        Dim secondsTemp As Short = Microsoft.VisualBasic.Mid(showHideValue, 7, 2)
        Dim milisecondsTemp As Short = Microsoft.VisualBasic.Mid(showHideValue, 10, 3)

        Dim timeInMS As Integer = hoursTemp * 3600000 + minutesTemp * 60000 + secondsTemp * 1000 + milisecondsTemp

        Return timeInMS
    End Function

    ''' <summary>
    ''' Converts the value of a Show or Hide column's cell to miliseconds.
    ''' </summary>
    ''' <param name="row">Row index in the DataGridView</param>
    ''' <param name="showColumnIsTrue">'True' if we want to convert the value that's in the Show column, 'False' if we want to
    ''' conver the value that's in the Hide column</param>
    ''' <returns>The cell's value (show or hide time) in miliseconds</returns>
    ''' <remarks></remarks>
    Public Function convertShowHideCellToMiliseconds(ByVal row As Integer, ByVal showColumnIsTrue As Boolean) As Integer
        Dim column As Short
        If showColumnIsTrue Then column = 1 Else column = 2

        Dim hoursTemp As Short = Microsoft.VisualBasic.Mid(frmMain.dgvSubtitles.Rows.Item(row).Cells.Item(column).Value, 1, 2)
        Dim minutesTemp As Short = Microsoft.VisualBasic.Mid(frmMain.dgvSubtitles.Rows.Item(row).Cells.Item(column).Value, 4, 2)
        Dim secondsTemp As Short = Microsoft.VisualBasic.Mid(frmMain.dgvSubtitles.Rows.Item(row).Cells.Item(column).Value, 7, 2)
        Dim milisecondsTemp As Short = Microsoft.VisualBasic.Mid(frmMain.dgvSubtitles.Rows.Item(row).Cells.Item(column).Value, 10, 3)

        Dim timeInMS As Integer = hoursTemp * 3600000 + minutesTemp * 60000 + secondsTemp * 1000 + milisecondsTemp

        Return timeInMS
    End Function

    Public Function convertMilisecondsToShowHideCell(ByVal timeInMS As Integer) As String

        Dim hoursTemp As Short = timeInMS \ 3600000
        Dim minutesTemp As Short = (timeInMS Mod 3600000) \ 60000
        Dim secondsTemp As Short = ((timeInMS Mod 3600000) Mod 60000) \ 1000
        Dim milisecondsTemp As Short = ((timeInMS Mod 3600000) Mod 60000) Mod 1000

        Dim cellData As String = Format(hoursTemp, "00") & ":" & Format(minutesTemp, "00") & ":" & Format(secondsTemp, "00") & "," & Format(milisecondsTemp, "000")
        Return cellData

    End Function

    ''' <summary>
    ''' Converts a value in miliseconds to that of a Show or Hide column's cell.
    ''' </summary>
    ''' <param name="row">Row index in the DataGridView</param>
    ''' <param name="showColumnIsTrue">'True' if we want to pass the value to the cell that's in the Show column, 'False' if we want to
    ''' pass the value to the cell that's in the Hide column</param>
    ''' <remarks></remarks>
    Public Sub convertMilisecondsToShowHideCell(ByVal timeInMS As Integer, ByVal row As Integer, ByVal showColumnIsTrue As Boolean)

        Dim column As Short
        If showColumnIsTrue Then column = 1 Else column = 2

        Dim hoursTemp As Short = timeInMS \ 3600000
        Dim minutesTemp As Short = (timeInMS Mod 3600000) \ 60000
        Dim secondsTemp As Short = ((timeInMS Mod 3600000) Mod 60000) \ 1000
        Dim milisecondsTemp As Short = ((timeInMS Mod 3600000) Mod 60000) Mod 1000

        Dim cellData As String = Format(hoursTemp, "00") & ":" & Format(minutesTemp, "00") & ":" & Format(secondsTemp, "00") & "," & Format(milisecondsTemp, "000")

        frmMain.dgvSubtitles.Rows.Item(row).Cells.Item(column).Value = cellData

    End Sub

    ''' <summary>Converts a string that is supposed to spread among multiple lines,
    ''' for example the Subtitle column of the DataGridView, using the default
    ''' separator, " | ".</summary>
    Public Function convertMultiLineTextToArray(ByVal text As String) As String()
        Dim returnArray(3) As String
        returnArray = Split(text, " | ", 3)
        Return returnArray
    End Function

    ''' <summary>Converts a string that is supposed to spread among multiple lines,
    ''' for example the Subtitle column of the DataGridView, using a custom separator.</summary>
    ''' <param name="text">The string that is to be splitted into an array.</param>
    ''' <param name="splitAtChar">The separator char or string. Usually " | ".</param>
    Public Function convertMultiLineTextToArray(ByVal text As String, ByVal splitAtChar As String) As String()
        Dim returnArray(3) As String
        returnArray = Split(text, splitAtChar, 3)
        Return returnArray
    End Function

    Public Sub updateTitle()
        Dim movieLoadedName As String

        If movieLoaded Then
            movieLoadedName = " [" & frmMain.dlgMovOpen.SafeFileName & "]"
        Else
            movieLoadedName = ""
        End If

        frmMain.Text = Application.ProductName & " - " & frmMain.dlgSubOpen.SafeFileName & movieLoadedName
    End Sub

    Public Function convertMilisecondsToFrames(ByVal timeInMS As Integer, ByVal FPS As Double) As Long

        Return timeInMS / (FPS / 1000)

    End Function

    Public Function convertFramesToMiliseconds(ByVal frames As Long, ByVal FPS As Double) As Integer

        Return frames * (FPS / 1000)

    End Function

    Public Sub ConvertToFPS(ByVal toFPS As Double)

        For i = 0 To frmMain.dgvSubtitles.RowCount - 1
            Dim startTime As Integer = convertShowHideCellToMiliseconds(i, True)
            Dim endTime As Integer = convertShowHideCellToMiliseconds(i, False)

            Dim startFrame As Long = convertMilisecondsToFrames(startTime, frmMain.currentFPS)
            Dim endFrame As Long = convertMilisecondsToFrames(endTime, frmMain.currentFPS)

            startTime = convertFramesToMiliseconds(startFrame, toFPS)
            endTime = convertFramesToMiliseconds(endFrame, toFPS)

            convertMilisecondsToShowHideCell(startTime, i, True)
            convertMilisecondsToShowHideCell(endTime, i, False)
        Next

    End Sub

    Public Function getSubtitleID(ByVal row As Integer) As Integer

        Return frmMain.dgvSubtitles.Rows(row).Cells.Item(0).Value

    End Function

    Public Function checkIfNewSubtitleExistsOnGivenTime(ByVal timeInMS As Integer) As Integer
        For i = 0 To frmMain.dgvSubtitles.RowCount - 1
            Dim startTime As Integer = convertShowHideCellToMiliseconds(i, True)
            Dim endTime As Integer = convertShowHideCellToMiliseconds(i, False)
            If i = 0 Then
                If timeInMS < startTime Then Return 0
            Else
                Dim endTimePrev As Integer = convertShowHideCellToMiliseconds(i - 1, False)
                If timeInMS > endTimePrev And timeInMS < startTime Then Return 0
            End If


            If timeInMS >= startTime And timeInMS <= endTime Then
                Return getSubtitleID(i)
            End If
        Next

        Return 0

    End Function

    Public Sub sortDGV()
        For i = 0 To frmMain.dgvSubtitles.RowCount - 1
            Try
                frmMain.dgvSubtitles.Rows.Item(i).Cells.Item("hiddenShow").Value = convertShowHideCellToMiliseconds(i, True)
            Catch
                MsgBox(i)
            End Try
        Next
        frmMain.dgvSubtitles.Sort(frmMain.dgvSubtitles.Columns.Item("hiddenShow"), System.ComponentModel.ListSortDirection.Ascending)
        For i = 0 To frmMain.dgvSubtitles.RowCount - 1
            frmMain.dgvSubtitles.Rows.Item(i).Cells.Item(0).Value = i + 1
        Next

        frmMain.mySubtitles.passDataGridViewToArray()
    End Sub

    ' Return True if another instance
    ' of this program is already running.
    Public Function AlreadyRunning() As Boolean
        ' Get our process name.
        Dim my_proc As Process = Process.GetCurrentProcess
        Dim my_name As String = my_proc.ProcessName

        ' Get information about processes with this name.
        Dim procs() As Process = _
            Process.GetProcessesByName(my_name)

        ' If there is only one, it's us.
        If procs.Length = 1 Then Return False

        ' If there is more than one process,
        ' see if one has a StartTime before ours.
        Dim i As Integer
        For i = 0 To procs.Length - 1
            If procs(i).StartTime < my_proc.StartTime Then _
                Return True
        Next i

        ' If we get here, we were first.
        Return False
    End Function

    Public Sub parseKnownLanguageFiles()
        ' Greek
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Greek.sel") = True Then
            frmMain.GreekToolStripMenuItem.Visible = True
        Else
            frmMain.GreekToolStripMenuItem.Visible = False
        End If

        ' Portuguese (Brazil)
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Brazilian Portuguese.sel") = True Then
            frmMain.BrazilianPortugueseToolStripMenuItem.Visible = True
        Else
            frmMain.BrazilianPortugueseToolStripMenuItem.Visible = False
        End If

        ' French
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\French.sel") = True Then
            frmMain.FrenchToolStripMenuItem.Visible = True
        Else
            frmMain.FrenchToolStripMenuItem.Visible = False
        End If

        ' Italian
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Italian.sel") = True Then
            frmMain.ItalianoToolStripMenuItem.Visible = True
        Else
            frmMain.ItalianoToolStripMenuItem.Visible = False
        End If

        ' Hebrew
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Hebrew.sel") = True Then
            frmMain.HebrewToolStripMenuItem.Visible = True
        Else
            frmMain.HebrewToolStripMenuItem.Visible = False
        End If

        ' Polish
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Polish.sel") = True Then
            frmMain.PolishToolStripMenuItem.Visible = True
        Else
            frmMain.PolishToolStripMenuItem.Visible = False
        End If

        ' Spanish
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Spanish.sel") = True Then
            frmMain.SpanishToolStripMenuItem.Visible = True
        Else
            frmMain.SpanishToolStripMenuItem.Visible = False
        End If

        ' Spanish (Alternative)
        If My.Computer.FileSystem.FileExists(Application.StartupPath & "\Languages\Spanish2.sel") = True Then
            frmMain.SpanishAlternativeToolStripMenuItem.Visible = True
        Else
            frmMain.SpanishAlternativeToolStripMenuItem.Visible = False
        End If
    End Sub

    Public Function VersionNumberInterpretation() As String
        Dim major As Short = My.Application.Info.Version.Major
        Dim minor As Short = My.Application.Info.Version.Minor
        Dim build As Short = My.Application.Info.Version.Build
        Dim revision As Integer = My.Application.Info.Version.Revision

        If build = 0 Then
            If minor = 0 Then
                If frmMain.VersionComment = "" Then
                    Return major & " (Revision " & revision & ")"
                Else
                    Return major & " " & frmMain.VersionComment & " (Revision " & revision & ")"
                End If
            Else
                If frmMain.VersionComment = "" Then
                    Return major & "." & minor & " (Revision " & revision & ")"
                Else
                    Return major & "." & minor & " " & frmMain.VersionComment & " (Revision " & revision & ")"
                End If
            End If
        Else
            If frmMain.VersionComment = "" Then
                Return major & "." & minor & "." & build & " (Revision " & revision & ")"
            Else
                Return major & "." & minor & "." & build & " " & frmMain.VersionComment & " (Revision " & revision & ")"
            End If
        End If
    End Function

End Module
